#include "callback_impl.h"
#include "../global/head.h"
#include "../xos/head.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos
{

    callback_impl::callback_impl()
    {
        m_bQuit = false;
        m_pThread = 0;
        m_pLock = 0;
        m_pEvent = 0;
    }

    callback_impl::~callback_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::clear_msg_list()
    {
        int nRet = 0;

        for( MSG_ITER iter = m_msg_list.begin(); iter != m_msg_list.end(); ++iter )
        {
            i_msg * p = *iter;
            p->release();
            p = 0;
        }

        m_msg_list.clear();

        return nRet;
    }

    void * callback_impl::thread( void * lpData )
    {
        callback_impl & obj = *( callback_impl * )lpData;

        while( !obj.m_bQuit )
        {
            obj.m_pEvent->wait( i_event::EVENT_WAIT_INFINITE );
            obj.run();
        }

        return 0;
    }

    int callback_impl::run()
    {
        int nRet = 0;

        bool bFinished = false;

        while( !m_bQuit && !bFinished )
        {
            i_runnable * pRun = 0;
            i_msg * p = 0;

            m_pLock->lock();
            if( m_msg_list.size() > 0 )
            {
                p = m_msg_list.front();
                m_msg_list.pop_front();
            }
            m_pLock->un_lock();

            if( p )
            {
                pRun = p->get_runnable( 0, 0 );
            }
            else
            {
                bFinished = true;
            }

            if( pRun )
            {
                pRun->run_task( p );
                p = 0;
            }
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            nRet = g_pXosImpl->create( i_xos::XOS_OBJ_EVENT, ( void ** )&m_pEvent );
        }

        if( 0 == nRet )
        {
            nRet = g_pXosImpl->create( i_xos::XOS_OBJ_LOCK, ( void ** )&m_pLock );
        }

        if( 0 == nRet )
        {
            nRet = g_pXosImpl->create( i_xos::XOS_OBJ_THREAD, ( void ** )&m_pThread );
            if( 0 == nRet )
            {
                nRet = m_pThread->create( thread, this );
            }
        }

        return nRet;
    }

    int callback_impl::term()
    {
        int nRet = 0;

        clear_msg_list();

        if( m_pThread )
        {
            m_bQuit = true;
            m_pEvent->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        if( m_pEvent )
        {
            m_pEvent->release();
            m_pEvent = 0;
        }

        if( m_pLock )
        {
            m_pLock->release();
            m_pLock = 0;
        }

        m_bQuit = false;

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::notify( i_msg * p )
    {
        int nRet = 0;

        m_pLock->lock();
        m_msg_list.push_back( p );
        m_pEvent->set_event();
        m_pLock->un_lock();

        return nRet;
    }

    int callback_impl::release()
    {
        int nRet = 0;

        term();
        put_back_lock();

        return nRet;
    }

} // xos
